[Panel]
Title=PHD Guiding interface
HidenTimer=0
AlwaysActive=0
NumToolbar1=0
NumToolbar2=0
NumComponent=36
component_0="Group_4;PHD host and port;2"
component_1="	Edit_9"
component_2="	Edit_10"
component_3="Group_1;Status;2"
component_4="	Button_1;Connect"
component_5="	Button_2;Disconnect"
component_6="	Label_5;Connection status"
component_7="	Label_6;Guiding status"
component_8="	Edit_1"
component_9="	Edit_2"
component_10="	Event_2;2;Timer;1"
component_11="	Event_0;0;Initialisation;"
component_12="	Event_5;5;Object identification click;"
component_13="Group_2;Lock Shift;2"
component_14="	Edit_3"
component_15="	Edit_4"
component_16="	Button_3;Set rates"
component_17="	Button_4;Enable;0"
component_18="	Label_7;Lock shift status"
component_19="	Spacer_1"
component_20="	Edit_6"
component_21="	Edit_5"
component_22="	Edit_7"
component_23="	Edit_8"
component_24="Group_5;Dither;2"
component_25="	Label_1;Shift"
component_26="	Label_2;Direction"
component_27="	Combo_1;"
component_28="	CheckList_1;26"
component_29="	Label_3;Stability"
component_30="	Label_4;Timeout"
component_31="	Combo_2;"
component_32="	Combo_3;"
component_33="	Button_5;Dither"
component_34="Group_3;Messages;1"
component_35="	Memo_1;50"

[button_1]
s="//"
"// Button Connect"
"var buf: string;"
"    count:integer;"
"begin"
"  TcpConnect(0,edit_9.text,edit_10.text,'100');"
"  buf:='{"method": "get_lock_shift_params", "id": 1003}';"
"  count:=length(buf);"
"  TcpWrite(0,buf,count);"
"end."
"//"


[button_2]
s="//"
"// Button Disconnect"
"begin"
"TcpDisconnect(0);"
"end."
"//"


[button_3]
s="//"
"// Button Set"
"var count : integer;"
"    buf:string;"
"    rx,ry,invalidfloat:double;"
"begin"
"if TcpConnected(0) then begin"
"  invalidfloat:=999999;"
"  StrtoFloatD(Edit_3.text,invalidfloat,rx);"
"  StrtoFloatD(Edit_4.text,invalidfloat,ry);"
"  if (abs(rx)>10000)or(abs(ry)>10000) then"
"    ShowMessage('Invalid rate values!')"
"  else begin"
"    buf:='{"method": "set_lock_shift_params", "params": [{"rate": [';"
"    buf:=buf+Edit_3.text+',';"
"    buf:=buf+Edit_4.text;"
"    buf:=buf+'], "units": "arcsec/hr", "axes": "RA/Dec"}], "id": 1001}'"
"    count:=length(buf);"
"    TcpWrite(0,buf,count);"
"    buf:='{"method": "get_lock_shift_params", "id": 1003}';"
"    count:=length(buf);"
"    TcpWrite(0,buf,count);"
"    SetI('INT1',1);"
"  end;"
"end;"
"end."
"//"


[button_4]
s="//"
"// Button Enable/Disable"
"var count : integer;"
"    buf,status:string;"
"begin"
"if TcpConnected(0) then begin"
"  if Button_4.Caption='Enable' then status:='true' else status:='false';"
"  buf:='{"method": "set_lock_shift_enabled", "params": [';"
"  buf:=buf+status;"
"  buf:=buf+'], "id": 1002}'"
"  count:=length(buf);"
"  TcpWrite(0,buf,count);"
"  if status='true' then  Button_4.Caption:='Disable' else Button_4.Caption:='Enable';"
"  buf:='{"method": "get_lock_shift_enabled", "id": 1004}';"
"  count:=length(buf);"
"  TcpWrite(0,buf,count);"
"  SetI('INT1',1);"
"end;"
"end."
"//"


[button_5]
s="//"
"// Button Dither"
"var count : integer;"
"    buf:string;"
"begin"
"if TcpConnected(0) then begin"
"    buf:='{"method": "dither", "params": [';"
"    buf:=buf+Combo_1.text+',';"
"    if Checklist_1.checked[0] then buf:=buf+'true,' else buf:=buf+'false,';"
"    buf:=buf+'{"pixels": '+Combo_2.text+',';"
"    buf:=buf+'"time": 5,';"
"    buf:=buf+'"timeout": '+Combo_3.text+'}],';"
"    buf:=buf+'"id": 1005}';"
"    count:=length(buf);"
"    TcpWrite(0,buf,count);"
"end;"
"end."
"//"


[event_2]
s="//"
"// Timer"
"// Process a PHD event"
"Procedure ProcessEvent(txt:string);"
"var eventname,rpcid,rpcresult,rpcerror,buf,fullmsg: string;"
"    PHDVersion,MsgVersion: string;"
"    attrib,value:Tstringlist;"
"    p,i:integer;"
"begin"
"GetSL('STRL1',attrib);"
"attrib.clear;"
"GetSL('STRL2',value);"
"value.clear;"
"try"
"fullmsg:=txt;"
"JsontoStringlist(txt,attrib,value);"
"p:=attrib.IndexOf('Event');    // PHD events"
"if p>=0 then begin"
"   eventname:=value[p];"
"   if eventname='GuideStep' then edit_2.text:='Guiding'"
"   else if eventname='StartGuiding' then edit_2.text:='Guiding'"
"   else if eventname='GuidingStopped' then edit_2.text:='Stopped'"
"   else if eventname='StarSelected' then edit_2.text:='Star Selected'"
"   else if eventname='StarLost' then edit_2.text:='Star lost'"
"   else if eventname='Paused' then edit_2.text:='Paused'"
"   else if eventname='Resumed' then edit_2.text:='Resumed'"
"   else if eventname='LockPositionSet' then edit_2.text:='Lock Position Set'"
"   else if eventname='CalibrationComplete' then edit_2.text:='Calibration Complete'"
"   else if eventname='StarSelected' then edit_2.text:='Star Selected'"
"   else if eventname='StartCalibration' then edit_2.text:='Start Calibration'"
"   else if eventname='CalibrationFailed' then edit_2.text:='Calibration Failed'"
"   else if eventname='CalibrationDataFlipped' then edit_2.text:='Calibration Data Flipped'"
"   else if eventname='LoopingExposures' then edit_2.text:='Looping Exposures'"
"   else if eventname='LoopingExposuresStopped' then edit_2.text:='Looping Exposures Stopped'"
"   else if eventname='Settling' then edit_2.text:='Settling'"
"   else if eventname='SettleDone' then edit_2.text:='Settle Done'"
"   else if eventname='GuidingDithered' then edit_2.text:='Guiding Dithered'"
"   else if eventname='LockPositionLost' then edit_2.text:='Lock Position Lost'"
"   else if eventname='Alert' then edit_2.text:='Alert'"
"   else if eventname='AppState' then begin"
"     i:=attrib.IndexOf('State');"
"     edit_2.text:=value[i];"
"   end"
"   else if eventname='Version' then begin"
"     i:=attrib.IndexOf('PHDVersion');"
"     if i>=0 then begin"
"        PHDVersion:=value[i];"
"        SetS('STR1',PHDVersion);"
"     end;"
"     i:=attrib.IndexOf('MsgVersion');"
"     if i>=0 then begin"
"        MsgVersion:=value[i];"
"        SetS('STR2',MsgVersion);"
"     end;"
"   end"
"   ;"
"end else begin"
"  p:=attrib.IndexOf('jsonrpc');   // Response to command"
"  if p>=0 then begin"
"     p:=attrib.IndexOf('id');"
"     rpcid:=value[p];"
"     i:=attrib.IndexOf('result');"
"     if i>=0 then rpcresult:=value[i]"
"     else begin"
"       i:=attrib.IndexOf('error.code');"
"       if i>=0 then begin"
"          rpcresult:='error'"
"          i:=attrib.IndexOf('error.message');"
"          if i>=0 then rpcerror:=value[i]"
"                  else rpcerror:='no response';"
"       end"
"       else rpcresult:='ok';"
"     end;"
"     if rpcid='1000' then begin   // get_app_state"
"       if rpcresult='error' then memo_1.lines.add('get_app_state'+' '+rpcresult+' '+rpcerror)"
"          else edit_2.text:=rpcresult;"
"     end"
"     else if rpcid='1001' then begin  // set_lock_shift_params"
"       if rpcresult='error' then memo_1.lines.add('set_lock_shift_params'+' '+rpcresult+' '+rpcerror);"
"     end"
"     else if rpcid='1002' then begin  // set_lock_shift_enabled"
"       if rpcresult='error' then memo_1.lines.add('set_lock_shift_enabled'+' '+rpcresult+' '+rpcerror);"
"     end"
"     else if rpcid='1003' then begin  // get_lock_shift_params"
"       if rpcresult='error' then"
"         memo_1.lines.add('get_lock_shift_params'+' '+rpcresult+' '+rpcerror)"
"       else begin"
"         i:=attrib.IndexOf('result.enabled');"
"         if i>=0 then begin"
"           if uppercase(trim(value[i]))='TRUE' then begin"
"              edit_5.text:='Tracking active';"
"              Button_4.Caption:='Disable';"
"           end"
"           else begin"
"              edit_5.text:='Tracking inactive';"
"              Button_4.Caption:='Enable';"
"           end;"
"         end"
"         else edit_5.text:='?';"
"         i:=attrib.IndexOf('result.axes');"
"         if i>=0 then edit_6.text:=value[i] else edit_6.text:='?';"
"         buf:='?';"
"         i:=attrib.IndexOf('result.rate.0');"
"         if i>=0 then buf:=value[i];"
"         i:=attrib.IndexOf('result.rate.1');"
"         if i>=0 then buf:=buf+' / '+value[i];"
"         edit_7.text:=buf;"
"         i:=attrib.IndexOf('result.units');"
"         if i>=0 then edit_8.text:=value[i] else edit_8.text:='?';"
"       end;"
"     end"
"     else if rpcid='1004' then begin  // get_lock_shift_enabled"
"       if rpcresult='error' then"
"         memo_1.lines.add('get_lock_shift_enabled'+' '+rpcresult+' '+rpcerror)"
"       else"
"         if uppercase(trim(rpcresult))='TRUE' then begin"
"            edit_5.text:='Tracking active';"
"            Button_4.Caption:='Disable';"
"         end"
"         else begin"
"            edit_5.text:='Tracking inactive';"
"            Button_4.Caption:='Enable';"
"         end;"
"     end;"
"  end;"
"end;"
"finally"
" attrib.clear;"
" value.clear;"
"end;"
"end;"
"//"
"// read and process all the events in queue"
"var"
"    buf:string;"
"    LockChanged,NTimer,count: integer;"
"begin"
"if TcpConnected(0) then begin"
"  // Refresh lock status"
"  GetI('INT1',LockChanged);"
"  if LockChanged>0 then begin"
"    buf:='{"method": "get_lock_shift_params", "id": 1003}';"
"    count:=length(buf);"
"    TcpWrite(0,buf,count);"
"    SetI('INT1',0);"
"  end;"
"  // refresh state"
"  GetI('INT2',NTimer);"
"  inc(NTimer);"
"  if NTimer=3 then begin"
"    buf:='{"method": "get_lock_shift_params", "id": 1003}';"
"    count:=length(buf);"
"    TcpWrite(0,buf,count);"
"  end;"
"  if NTimer>5 then begin"
"    buf:='{"method": "get_app_state", "id": 1000}';"
"    count:=length(buf);"
"    TcpWrite(0,buf,count);"
"    NTimer:=0;"
"  end;"
"  SetI('INT2',NTimer);"
"  Edit_1.text:='Connected';"
"  // read and process messages from PHD"
"  repeat"
"  if TcpRead(0,buf,'') then"
"     ProcessEvent(buf);"
"  until buf='';"
"end"
"else begin"
"  Edit_1.text:='Disconnected';"
"  Edit_2.text:='';"
"  Edit_5.text:='';"
"  Edit_6.text:='';"
"  Edit_7.text:='';"
"  Edit_8.text:='';"
"end;"
"end."
"//"


[event_0]
s="//"
"// Initialisation"
"var buf: string;"
"    count: integer;"
"begin"
"// Hide dithering by default as this function is better used in the capture software."
"// Comment the following line if you need it, for example if you shoot with a standalone camera."
"Group_5.visible:=false;"
"//"
"edit_1.text :='Disconnected';"
"edit_1.readonly:=true;"
"edit_1.enabled:=false;"
"edit_2.readonly:=true;"
"edit_2.enabled:=false;"
"edit_5.readonly:=true;"
"edit_5.enabled:=false;"
"edit_6.readonly:=true;"
"edit_6.enabled:=false;"
"edit_7.readonly:=true;"
"edit_7.enabled:=false;"
"edit_8.readonly:=true;"
"edit_8.enabled:=false;"
"edit_9.text:='localhost';"
"edit_10.text:='4400';"
"Combo_1.Style:=csDropDownList;"
"Combo_1.clear;"
"Combo_1.Items.Add('1');"
"Combo_1.Items.Add('2');"
"Combo_1.Items.Add('3');"
"Combo_1.Items.Add('5');"
"Combo_1.Items.Add('10');"
"Combo_1.ItemIndex:=0;"
"CheckList_1.clear;"
"CheckList_1.Items.Add('RA only');"
"CheckList_1.Checked[0]:=false;"
"Combo_2.Style:=csDropDownList;"
"Combo_2.clear;"
"Combo_2.Items.Add('0.2');"
"Combo_2.Items.Add('0.5');"
"Combo_2.Items.Add('1');"
"Combo_2.Items.Add('1.5');"
"Combo_2.ItemIndex:=1;"
"Combo_3.Style:=csDropDownList;"
"Combo_3.clear;"
"Combo_3.Items.Add('5');"
"Combo_3.Items.Add('10');"
"Combo_3.Items.Add('20');"
"Combo_3.Items.Add('30');"
"Combo_3.Items.Add('60');"
"Combo_3.ItemIndex:=2;"
"Edit_3.Text:='0';"
"Edit_4.Text:='0';"
"if TcpConnected(0) then begin"
"  buf:='{"method": "get_app_state", "id": 1000}';"
"  count:=length(buf);"
"  TcpWrite(0,buf,count);"
"  buf:='{"method": "get_lock_shift_params", "id": 1003}';"
"  count:=length(buf);"
"  TcpWrite(0,buf,count);"
"  SetI('INT1',1); // lock changed marker"
"  SetI('INT2',0); // timer loop counter"
"end;"
"end."
"//"


[event_5]
s="//"
"// Object identification event"
"const"
"  crlf=#13 + #10;"
"function NextVal(var txt: string; key:string): double;"
"var buf: string;"
"    p: integer;"
"    dv: double;"
"begin"
"  dv:=0;"
"  p:=pos(key,txt);"
"  if p>0 then begin"
"    buf:=copy(txt,1,p-1);"
"    delete(txt,1,p);"
"    StrtoFloatD(buf,dv,result);"
"  end"
"  else result:=dv;"
"end;"
"var str,buf,dx,dy: string;"
"    p: integer;"
"    x,y,sx,sy,de: double;"
"begin"
"// Info about object"
" getS('SelectionText',str)"
" // Get RA"
" p:=pos(chr(9),str);"
" buf:=copy(str,1,p-1);"
"  delete(str,1,p);"
"// Get Dec"
" p:=pos(chr(9),str);"
" buf:=copy(str,1,p-1);"
" delete(str,1,p);"
" if not StrToDE(buf,de) then begin memo_1.lines.add(rserror+' DE! '+buf);exit;end;"
" getS('DescriptionText',str)"
" p:=pos(rsHourlyMotion,str);"
" if p>0 then begin"
"    delete(str,1,p+length(rsHourlyMotion)+1);"
"    p:=pos('dRA:',str);"
"    delete(str,1,p+3);"
"    p:=pos(' dDec:',str);"
"    dx:=copy(str,1,p-1);"
"    delete(str,1,p+5);"
"    p:=pos(crlf,str);"
"    dy:=copy(str,1,p-1);"
"    x:=0;"
"    if copy(dx,1,1)='-' then sx:=-1 else sx:=1;"
"    x:=x+3600*abs(NextVal(dx,'h'));"
"    x:=x+60*abs(NextVal(dx,'m'));"
"    x:=x+abs(NextVal(dx,'s'));"
"    y:=0;"
"    if copy(dy,1,1)='-' then sy:=-1 else sy:=1;"
"    y:=y+3600*abs(NextVal(dy,rsdeg));"
"    y:=y+60*abs(NextVal(dy,rsmin));"
"    y:=y+abs(NextVal(dy,rssec));"
"    x:=15*sx*x;"
"    x:=x*cos(de*pi/180);"
"    y:=-sy*y;"
"    Edit_3.text:=FormatFloat('0.00',x);"
"    Edit_4.text:=FormatFloat('0.00',y);"
" end"
" else begin"
"    Edit_3.text:='0';"
"    Edit_4.text:='0';"
" end;"
"end."
"//"

